//---------------------------------------------------------------------
//  This file is part of the Background Motion solution.
// 
//  Copyright (C) Mindscape (TM).  All rights reserved.
//  http://www.mindscape.co.nz
// 
//  THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//  PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;

using Mindscape.BackgroundMotion.Core.Utilities;

namespace Mindscape.BackgroundMotion.Core.Model
{
  /// <summary>
  /// Static gateway which allows manipulation of a unit of work in the system
  /// </summary>
  public static class UnitOfWork
  {
    private static int _depth;

    /// <summary>
    /// Begins this instance.
    /// </summary>
    /// <returns></returns>
    public static IUnitOfWork Begin()
    {
      IUnitOfWork unitOfWork = ServiceLocator.Get<IUnitOfWorkFactory>().Create();
      unitOfWork.Disposed += new EventHandler(UnitOfWorkDisposedEvent);

      Invariant.IsTrue(_depth >= 0);

      _depth++;

      ContextItemsBroker.SetItem(CurrentContextKey, unitOfWork);

      return unitOfWork;
    }

    /// <summary>
    /// Completes this instance.
    /// </summary>
    public static void Complete()
    {
      Current.Complete();
    }

    /// <summary>
    /// Gets the current unit of work
    /// </summary>
    /// <returns></returns>
    public static T GetCurrent<T>()
      where T : IUnitOfWork
    {
      return ContextItemsBroker.GetItem<T>(CurrentContextKey);
    }

    /// <summary>
    /// Gets the current repository.
    /// </summary>
    /// <returns></returns>
    public static IRepository<T> GetRepository<T>()
      where T : class, IIdentifiable
    {
      return Current.GetRepository<T>();
    }

    /// <summary>
    /// Gets the current unit of work
    /// </summary>
    /// <value>The current.</value>
    private static IUnitOfWork Current
    {
      get { return GetCurrent<IUnitOfWork>(); }
    }

    /// <summary>
    /// Fires when a unit of work is being disposed
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    private static void UnitOfWorkDisposedEvent(object sender, EventArgs e)
    {
      ContextItemsBroker.RemoveItem(CurrentContextKey);

      _depth--;

      Invariant.IsTrue(_depth >= 0);
    }

    /// <summary>
    /// Gets the current context key.
    /// </summary>
    /// <value>The current context key.</value>
    private static string CurrentContextKey
    {
      get { return "UnitOfWork" + _depth; }
    }
  }
}